WPF Diagrams includes the DiagramXmlSerializer class for saving diagrams to XML and loading them from XML. The DiagramXmlSerializer class works with Diagram objects, ShapeNode, TitleNode and CommentNode nodes, and DiagramConnection connections. If you create a custom diagram type with custom node or connection classes, and you want to use DiagramXmlSerializer to save and load your diagrams, you will need to extend it to handle your custom node or connection classes.
To do this, override the following methods:
- For custom node classes: SerializeNodeCore (serialization) and CreateNode (deserialization)
- For custom connection classes: SerializeConnectionCore (serialization) and CreateConnection (deserialization)
- For custom diagram classes: CreateDiagram (deserialization)
The Serialize methods should return a XElement which identifies the type of node or connection in a way that will be recognised by the deserialization methods. The Serialize methods should populate any custom data specified by the node or connection class (this can also be done through the OnSerializeCustomNodeData and OnDeserializeCustomConnectionData callbacks, but these may be set by the user and should therefore not be relied on for essential custom data). The Serialize methods should call the base class implementation if they want default serialization behaviour for the node or connection – note that the DiagramXmlSerializer base implementation handles only the built-in shape, title and comment node types.
protected override XElement SerializeNodeCore(DiagramNode node) { if (node is BranchNode) { return new XElement("BranchNode"); } return base.SerializeNodeCore(node); }
The Create (deserialize) methods should return an object (node, connection or diagram) appropriate to the XElement passed in. The Create methods should load any custom data specified by the node or connection class (this can also be done through the OnDeserializeCustomNodeData and OnDeserializeCustomConnectionData callbacks, but these may be set by the user and should therefore not be relied on for essential custom data). The Create methods should call the base class implementation if they want the default deserialization behaviour for the XML element.
protected override DiagramNode CreateNode(XElement xml) { if (xml.Name.LocalName == "BranchNode") { return new BranchNode(); } return base.CreateNode(xml); }
Deserializing custom connection types requires a little more code because connections need to be hooked up to their connection points, and need to call the correct constructor depending on whether there were segments associated with the connection:
protected override DiagramConnection CreateConnection(XElement xml, DiagramConnectionPoint source, DiagramConnectionPoint destination, IList<DiagramConnectionSegment> segments) { if (xml.Name == ActivityDiagramConnectionElementName) { if (segments.Count == 0) { return new ActivityDiagramConnection(source, destination); } else { return new ActivityDiagramConnection(source, destination, segments); } } return base.CreateConnection(xml, source, destination, segments); }